﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Text;
using WooCoo.Tools;

namespace WooCoo.IoC
{
    /// <summary>
    /// 采用MEF做为IOC容器
    /// </summary>
    public class MEFAdapter : IContainer
    {

        Lazy<CompositionContainer> lazyContainer;

        public MEFAdapter(Lazy<CompositionContainer> lazyContainer)
        {
            if (lazyContainer == null) throw new ArgumentNullException("lazyContainer");
            this.lazyContainer = lazyContainer;
        }
        public MEFAdapter(Func<CompositionContainer> lazyContainer)
            : this(new Lazy<CompositionContainer>(lazyContainer))
        {
        }
        public MEFAdapter(CompositionContainer container)
            : this(new Lazy<CompositionContainer>(() => container))
        {
            //AggregateCatalog catalog = new AggregateCatalog(new DirectoryCatalog(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory)));
            //ServiceLocator = new MEFServiceLocatorAdapter(new CompositionContainer(catalog));
        }

        #region IContainer Interface
        public object Instance
        {
            get { return lazyContainer.Value; }
        }

        public T GetExportedValue<T>()
        {
            var container = lazyContainer.Value;
            T result = default(T);
            try
            {
                result = container.GetExportedValue<T>();
            }
            catch (ImportCardinalityMismatchException ex)
            {
            }
            return result;
        }

        public T GetExportedValue<T>(string contractName)
        {
            var container = lazyContainer.Value;
            T result = default(T);
            try
            {
                result = container.GetExportedValue<T>(contractName);
            }
            catch (ImportCardinalityMismatchException ex)
            {
            }
            return result;
        }

        public IEnumerable<T> GetExportedValues<T>()
        {
            var container = lazyContainer.Value;
            return container.GetExportedValues<T>();
        }

        public IEnumerable<T> GetExportedValues<T>(string contractName)
        {
            var container = lazyContainer.Value;
            return container.GetExportedValues<T>(contractName);
        }

        public bool TryGetExports(string contractName, out object export)
        {
            var importd = new System.ComponentModel.Composition.Primitives.ImportDefinition
                (o => o.ContractName == contractName, contractName, ImportCardinality.ZeroOrOne, true, true);
            var exportlist = this.lazyContainer.Value.GetExports(importd);
            if (exportlist.Count() != 0)
            {
                export = exportlist.First().Value;
                return true;
            }
            export = null;
            return false;
        }

        public bool TryGetExports(Type exportType, string contractName, out object export)
        {
            var importd = new System.ComponentModel.Composition.Primitives.ImportDefinition
                (o => o.ContractName == contractName, contractName, ImportCardinality.ZeroOrOne, true, true);

            var exportList = this.lazyContainer.Value.GetExports(importd);
            if(exportList.Count()!=0)
            {                
                object val = exportList.First().Value;
                try
                {
                    export = TypeHelper.CoerceValue(exportType, val);
                    return true;
                }
                catch
                {
                    export = null;
                    return false;
                }
                
            }
            export = null;
            return false;
            //var importd = new System.ComponentModel.Composition.Primitives.ImportDefinition
            //    (o => o.Metadata. == contractName, contractName, ImportCardinality.ZeroOrOne, true, true);
        }
        #endregion
    }
}
